package cn.wwcyc.controller;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.wwcyc.config.GetHttpSessionConfigurator;
import cn.wwcyc.dao.ModbusDao;
import cn.wwcyc.domain.*;
import cn.wwcyc.service.TjLogService;
import cn.wwcyc.service.UserService;
import cn.wwcyc.utils.JWTUtil;
import com.auth0.jwt.JWT;

import com.serotonin.modbus4j.exception.ErrorResponseException;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import javax.xml.ws.handler.MessageContext;
//import com.oracle.webservices.internal.api.message.MessageContext;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

@ServerEndpoint(value="/websocket" ,configurator= GetHttpSessionConfigurator.class)
@Component  //注意，尽管这里用了@Component注解，但是此对象仍不是单例的。。！！
public class ServerEndPoint {
    private static Set<ServerEndPoint> clients = Collections.synchronizedSet(new HashSet<>());

    private static UserService staticUserService;

    private static TjLogService logService;
    private Session session;
    private User user;

    //    private HttpSession httpSession; 注意，因为是vue前后端分离的项目，这里没有httpsession对象！
    static {
        staticUserService = (UserService) SpringUtil.getBean(UserService.class);
        logService = (TjLogService) SpringUtil.getBean(TjLogService.class);
    }

    @OnOpen
    public void onOpen(Session session, EndpointConfig config) {
        System.out.println(session + "新连接加入！");
        this.session = session;
        session.setMaxTextMessageBufferSize(10*1024*1024);
        session.setMaxBinaryMessageBufferSize(10*1024*1024);
        clients.add(this);

//        this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());

        String requestUrl = session.getRequestURI().toString();
        // 解析URL中的查询参数
        Map<String, List<String>> params = session.getRequestParameterMap();
        // 尝试从查询参数中获取token
        System.out.println("==================Request URL: " + requestUrl);
//        System.out.println("==================Query Parameters: " + params);

        String token = params.get("token").get(0);

        if (token != null) {
            // 对token进行解码，如果它被编码过（通常情况）
            try {
                token = URLDecoder.decode(token, StandardCharsets.UTF_8.name());
            } catch (Exception e) {
                e.printStackTrace();
                // 处理解码异常
            }
            // 进一步处理token，如验证等
            String userId = JWT.decode(token).getAudience().get(0);
            user = staticUserService.getById(userId);
        }
        if (user == null) {
            try {
                session.getBasicRemote().sendText("{\"type\":\"error\",\"data\":\"token无效\"}");
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("收到消息：" + message);
//        {"type":"batchstop","data":[
//                {"id":3,"jh":null,"ip":"10.10.10.10","dw":1,"gx":null,"dwObj":{"id":1,"dwname":"文卫采油厂","dwjb":100,"pid":null,"children":null},"gxObj":null},
//                {"id":1,"jh":"qwqw","ip":"192.168.3.130","dw":1,"gx":0,"dwObj":{"id":1,"dwname":"文卫采油厂","dwjb":100,"pid":null,"children":null},"gxObj":{"id":0,"name":"明1线","dw":null,"dwObj":null}},
//                {"id":0,"jh":"192.168.3.130","ip":"192.168.3.130","dw":1,"gx":null,"dwObj":{"id":1,"dwname":"文卫采油厂","dwjb":100,"pid":null,"children":null},"gxObj":null},
//                {"id":2,"jh":"192.168.3.130","ip":"192.168.3.130","dw":2,"gx":5,"dwObj":{"id":2,"dwname":"采油管理一区","dwjb":210,"pid":null,"children":null},"gxObj":{"id":5,"name":"wewew","dw":null,"dwObj":null}}
//            ]
//        }
        JSONObject json = null;
        try {
            json = JSONUtil.parseObj(message);
        } catch (Exception e) {
            System.out.println(message);
            return;
        }

        if (json.getStr("type").equals("batchstop")) {
            List<TDjxx> tDjxxList = json.getBeanList("data", TDjxx.class);
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        batchTj(user, tDjxxList);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            });
            t.start();
        }

        System.out.println("size:------------" + clients.size());
    }

    @OnClose
    public void onClose(Session session) {
        System.out.println(session + "连接已关闭！");
        clients.remove(this);
    }

    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println(session + "发生错误");
        error.printStackTrace();
    }


    public R<String> batchTj(User user, List<TDjxx> tDjxxList) throws InterruptedException, IOException {
//        System.out.println(tDjxxList);
//        Thread.sleep(10000);
        System.out.println("开始执行");
//        User user = JWTUtil.getCurrentUser();

        //获取ip地址
        String ip = "";
//        String ip = httpSession.getAttribute("loginip").toString();
//        System.out.println("--------------"+request.getRemoteHost());
//        System.out.println("--------------"+request.getRemoteAddr());
//        System.out.println(tDjxxList);
        //计算用时时间
        long startTime = System.currentTimeMillis();
        List<TDjxx> errDjList = new ArrayList<>();
        for (TDjxx tDjxx : tDjxxList) {
            try {
//                session.getBasicRemote().sendText("正在停止" + tDjxx.getJh() + "单井抽油机");
//                clients.forEach(client -> {
//                    if (client.user.getId().equals(user.getId())) {
//                        client.session.getBasicRemote().sendText("正在停止" + tDjxx.getJh() + "单井抽油机");
//                    }
//                });//这里如果用forEach便利，会报sendText有未处理的异常！！，以后研究！！
                for( ServerEndPoint client : clients){
                    if (client.user.getId().equals(user.getId())) {
                        WSMessage wsMessage = new WSMessage();
                        wsMessage.setMessage("正在停止" + tDjxx.getJh() + "单井抽油机");
                        wsMessage.setType("batchstop_info");
                        client.session.getBasicRemote().sendText(JSONUtil.toJsonStr(wsMessage));
//                        client.session.getBasicRemote().sendText("正在停止" + tDjxx.getJh() + "单井抽油机");
                    }
                }
                ModbusDao.setCoilStatus(tDjxx.getIp(), 1, 10007, true);
//                session.getBasicRemote().sendText(tDjxx.getJh() + "单井抽油机停机成功");
                for( ServerEndPoint client : clients){
                    if (client.user.getId().equals(user.getId())) {
                        WSMessage wsMessage = new WSMessage();
                        wsMessage.setMessage(tDjxx.getJh() + "单井抽油机停机成功");
                        wsMessage.setType("batchstop_info");
                        client.session.getBasicRemote().sendText(JSONUtil.toJsonStr(wsMessage));
//                        client.session.getBasicRemote().sendText(tDjxx.getJh() + "单井抽油机停机成功");
                    }
                }
            } catch (ModbusInitException e1) {
                errDjList.add(tDjxx);
                for( ServerEndPoint client : clients){
                    if (client.user.getId().equals(user.getId())) {
                        WSMessage wsMessage = new WSMessage();
                        wsMessage.setMessage(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e1.getMessage());
                        wsMessage.setType("batchstop_err");
                        client.session.getBasicRemote().sendText(JSONUtil.toJsonStr(wsMessage));
//                        client.session.getBasicRemote().sendText(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e1.getMessage());
                    }
                }
//                session.getBasicRemote().sendText(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e1.getMessage());
//                return R.error(WWExceptionEnum.Modbus_ERROR);
            } catch (ModbusTransportException e2) {
                errDjList.add(tDjxx);
                for( ServerEndPoint client : clients){
                    if (client.user.getId().equals(user.getId())) {
                        WSMessage wsMessage = new WSMessage();
                        wsMessage.setMessage(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e2.getMessage());
                        wsMessage.setType("batchstop_err");
                        client.session.getBasicRemote().sendText(JSONUtil.toJsonStr(wsMessage));
//                        client.session.getBasicRemote().sendText(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e2.getMessage());
                    }
                }
//                session.getBasicRemote().sendText(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e2.getMessage());
//                return R.error(WWExceptionEnum.Modbus_ERROR);
            } catch (ErrorResponseException e3) {
                errDjList.add(tDjxx);
                for( ServerEndPoint client : clients){
                    if (client.user.getId().equals(user.getId())) {
                        WSMessage wsMessage = new WSMessage();
                        wsMessage.setMessage(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e3.getMessage());
                        wsMessage.setType("batchstop_err");
                        client.session.getBasicRemote().sendText(JSONUtil.toJsonStr(wsMessage));
//                        client.session.getBasicRemote().sendText(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e3.getMessage());
                    }
                }
//                session.getBasicRemote().sendText(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e3.getMessage());
//                return R.error(WWExceptionEnum.Modbus_ERROR);
            } catch (Exception e) {
                errDjList.add(tDjxx);
                for( ServerEndPoint client : clients){
                    if (client.user.getId().equals(user.getId())) {
                        WSMessage wsMessage = new WSMessage();
                        wsMessage.setMessage(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e.getMessage());
                        wsMessage.setType("batchstop_err");
                        client.session.getBasicRemote().sendText(JSONUtil.toJsonStr(wsMessage));
//                        client.session.getBasicRemote().sendText(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e.getMessage());
                    }
                }
//                session.getBasicRemote().sendText(tDjxx.getJh() + "单井抽油机停机失败，原因：" + e.getMessage());
//                return R.error(WWExceptionEnum.SYSTEM_ERROR);
            }
        }

        if (errDjList.size() == 0) {
            TjLog oplog = new TjLog();
            oplog.setUsername(user.getUsername());
            oplog.setIp(ip);
            oplog.setOptype("批量停机");
            String opcontent = "批量停机" + tDjxxList.size() + "个抽油机，成功" + tDjxxList.size() + "个; 成功井号：";
            for (TDjxx tDjxx : tDjxxList) {
                opcontent += tDjxx.getJh() + ", ";
            }
            opcontent = opcontent.substring(0, opcontent.length() - 2);
            oplog.setOpcontent(opcontent);
            oplog.setCreatedate(new Date());
            logService.save(oplog);
            Long endTime = System.currentTimeMillis();
            for( ServerEndPoint client : clients){
                if (client.user.getId().equals(user.getId())) {
                    WSMessage wsMessage = new WSMessage();
                    wsMessage.setMessage(opcontent);
                    wsMessage.setType("batchstop_over");
                    client.session.getBasicRemote().sendText(JSONUtil.toJsonStr(wsMessage));
                }
            }
            return R.success("耗时" + (endTime - startTime));
        } else {
            TjLog oplog = new TjLog();
            oplog.setUsername(user.getUsername());
            oplog.setIp(ip);
            oplog.setOptype("批量停机");
            String opcontent = "批量停机" + tDjxxList.size() + "个抽油机，" +
                    "成功" + (tDjxxList.size() - errDjList.size()) + "个; "
                    + "失败" + errDjList.size() + "个; ";
            if (tDjxxList.size() - errDjList.size() > 0) {
                opcontent += "成功井号：";
                for (TDjxx tDjxx : tDjxxList) {
                    if (!errDjList.contains(tDjxx)) {
                        opcontent += tDjxx.getJh() + ", ";
                    }
                }
                opcontent = opcontent.substring(0, opcontent.length() - 2);
            }
            if (errDjList.size() > 0) {
                opcontent += "; 失败井号：";
                for (TDjxx tDjxx : tDjxxList) {
                    if (errDjList.contains(tDjxx)) {
                        opcontent += tDjxx.getJh() + ", ";
                    }
                }
                opcontent = opcontent.substring(0, opcontent.length() - 2);
            }

            oplog.setOpcontent(opcontent);
            oplog.setCreatedate(new Date());
            logService.save(oplog);

            String msg = "批量停机错误！井号：";
            for (TDjxx tDjxx : errDjList) {
                msg += tDjxx.getJh() + ", ";
            }
            msg = msg.substring(0, msg.length() - 2);
            Long endTime = System.currentTimeMillis();
            msg = "耗时" + (endTime - startTime) + "，" + msg;
            for( ServerEndPoint client : clients){
                if (client.user.getId().equals(user.getId())) {
                    WSMessage wsMessage = new WSMessage();
                    wsMessage.setMessage(opcontent);
                    wsMessage.setType("batchstop_over");
                    client.session.getBasicRemote().sendText(JSONUtil.toJsonStr(wsMessage));
                }
            }
            return R.error(22002, msg);
        }
    }

}
